The Null Variable
The system variable !NULL is a special variable of type Undefined. Unlike a variable that is truly undefined, the value !NULL can be assigned to other variables and used in comparisons.
Assignment Syntax
Use any of the following to assign the value !NULL to a variable:
variable = !NULL
variable = [ ]
variable = { }
!NULL can be assigned to an existing variable, undefining it and freeing its memory.
A = 10
A = !NULL
PRINT, A
IDL Prints:
!NULL
Comparison
The !NULL variable is equivalent to:
- an undefined variable
- a null pointer
- a null object
Use the comparison operators EQ and NE to determine whether a variable has a defined value. (Null pointers and null objects have type Pointer and Objref, respectively, but have no defined values.)
For example, suppose the variable U
has not been defined in the current IDL session. Then:
PRINT, U EQ !NULL
IDL prints:
1
showing that U
has no defined value.
As another example:
p = PTR_NEW(5)
PTR_FREE, p
PRINT, p EQ !NULL
IDL prints:
1
showing that p now refers to a null pointer.
Similarly, for objects:
obj = IDL_Container()
obj.Cleanup
PRINT, obj EQ !NULL
IDL prints:
1
Assigning Function Return Values
To discard the return value from a function, assign it to !NULL. For example, suppose you wanted to find the subscripts of both the minimum and maximum values in an array using the MAX function. In the following statement:
!NULL = MAX(array, subscript_max, SUBSCRIPT_MIN=subscript_min)
the MAX function returns the subscripts of both the maximum and minimum values in the subscript_max
and subscript_min
variables, discarding the return value (the actual value of the largest element).
Null Values As Array Elements
Null values are ignored when they appear as array elements. For example:
array = [3.0, !NULL, 2.5, 1.9, !NULL, 0.7]
PRINT, array & HELP, array
IDL prints:
3.00000 2.50000 1.90000 0.700000
ARRAY FLOAT = Array[4]
As a result, a variable set equal to !NULL can be thought of as an empty element in an array specification. Thinking of a null variable in this way makes it easy to add variables to an array without first checking to ensure that the array is defined. For example, you might use code like the following when building an array variable from values determined at runtime:
array = [ ]
WHILE some_condition
DO BEGIN
IF some_other_condition
THEN array = [array, new_element
]
...
ENDWHILE
Here, the fact that we intialize the variable array
to the value !NULL eliminates the need to test whether array
is defined in each iteration of the WHILE loop. On the first iteration, array
is equal to !NULL, and serves as an empty element that is ignored after the first variable with a defined value is added.
Similarly, if we want to construct an array by adding values in another dimension, an array containing only a null value can serve as a placeholder for an entire dimension in the array:
array = [ ]
WHILE some_condition
DO BEGIN
IF some_other_condition
THEN array = [[array], [new_array
]]
...
ENDWHILE
Here we end up creating a two-dimensional array, with each iteration adding a new array to the second dimension.
Note: The value !NULL cannot be used as a “missing value” placeholder in an array. Array elements equal to !NULL are ignored entirely, as if they were not present at all.
Null Values As Subscripts
When indexing into an array, if any of the subscripts are equal to !NULL, then the result is !NULL. For example:
array = [3.0, 2.5, 1.9, 0.7]
HELP, array[!NULL]
IDL prints:
<Expression> UNDEFINED = !NULL
As another example, using a multi-dimensional array:
array = FINDGEN(5,10,20)
HELP, array[2:3, !NULL, *]
IDL prints:
<Expression> UNDEFINED = !NULL
This is especially useful when the array appears on the left-hand side of an assignment, as the assignment is then ignored. For example:
array = FINDGEN(5,10,20)
indices = WHERE(array LT 0, /NULL)
array[indices] = -1
PRINT, MIN(array)
IDL prints:
0.000000
Since none of the elements were negative, the WHERE with /NULL returned !NULL as the result. This !NULL was then ignored when the assignment was performed. For more examples of using WHERE with !NULL, see the topic on Conditionally Altering Array Elements.
Null Values as Structures
The CREATE_STRUCT function will treat a !NULL argument as an anonymous structure with no fields. This makes it easy to add fields and values to a stucture using CREATE_STRUCT without first checking to ensure that the structure is defined. For example, you might use code like the following when building a structure variable from the contents of an array at runtime:
struct = { }
FOREACH element, array, index DO BEGIN
fieldname = 'Field'+STRTRIM(index,2)
some_value = some_operation_on(element)
struct = CREATE_STRUCT(struct, fieldname, some_value)
ENDFOREACH
Here, the fact that we intialize struct
to the value !NULL eliminates the need to test whether struct
is defined in each iteration of the FOREACH loop. On the first iteration, struct
is equal to !NULL, and serves as an anonymous structure with no fields, allowing an additional field to be added on each iteration.
Note: The value of a structure field cannot be set to !NULL.
Null Values in Pointers
When creating an IDL pointer variable, the value !NULL may be used as a placeholder to indicate that this is a valid pointer, whose value has not yet been assigned. For example, with an invalid pointer:
p = PTR_NEW()
print, *p
IDL throws the following error:
% Unable to dereference NULL pointer: P.
% Execution halted at: $MAIN$
Now, using !NULL as the value:
p = PTR_NEW(!NULL)
print, *p
IDL prints:
!NULL
Note: The ALLOCATE_HEAP keyword to PTR_NEW and PTRARR is equivalent to assigning the !NULL value to the pointers.
Null Value as an Input Argument
The !NULL value is useful for assignment, comparison, and for array concatenation. In most other cases, the !NULL value is treated as an undefined variable. For example, in routine calls:
f = FFT(!NULL)
IDL throws the following error:
% FFT: Expression must be an array in this context: <UNDEFINED>.
% Execution halted at: $MAIN$
Similarly, when trying to convert a !NULL value to a different type:
x = FIX(!NULL)
IDL throws the following error:
% FIX: Variable is undefined: <UNDEFINED>.
% Execution halted at: $MAIN$
The same error occurs when trying to convert a !NULL value to a string:
x = STRING(!NULL)
IDL throws the following error:
% STRING: Variable is undefined: <UNDEFINED>.
% Execution halted at: $MAIN$
The following table lists the cases where !NULL is accepted as an input argument:
Routine |
Result |
---|---|
ARG_PRESENT |
0 |
HASH indexing |
!NULL |
HELP |
"<Expression> UNDEFINED = !NULL" |
IDL_Container::Remove |
Quietly returns |
ISA |
0 |
ISA with /NULL keyword |
1 |
KEYWORD_SET |
0 |
LIST indexing |
!NULL |
N_ELEMENTS |
0 |
OBJ_ISA |
0 |
OBJ_VALID |
0 |
|
"!NULL" |
PTR_VALID |
0 |
SIZE |
[0, 0, 0] |
In all other routines, IDL will throw an "undefined variable" error.
Using Null Values for Keywords
You can also pass in !NULL for keyword values.
In most cases, passing in !NULL as a keyword value will cause the calling routine to quietly ignore the keyword (as if it was not passed in at all). However, you may wish to write a routine that handles !NULL keyword values differently. The following rules are used when !NULL is passed as a keyword value:
1. If the keyword is handled directly by the called routine, then the keyword value will be set equal to !NULL. The called routine could use ISA(/NULL) to test for this, and take appropriate action (either ignore the keyword or do something else).
2. If the keyword is handled as part of _REF_EXTRA, then the keyword value will also be set to !NULL. The routine could use SCOPE_VARFETCH to retrieve this value, or pass the keyword on to other routines.
3. If the keyword is handled as part of _EXTRA, then the keyword value will not be included in the _EXTRA structure, and will be treated just as if the keyword was never passed in.
See Keyword Inheritance for the differences between _REF_EXTRA and _EXTRA.